<?php

namespace app\controller\admin\module\menu\components;

use app\components\traits\Singleton;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;

class SecondaryMethod
{
    use Singleton;
    protected string $modelName = 'menu';
    private array $search = [//所有匹配的值，对应能访问的名字
        'name' => '@auth-name',
        'method_alias' => '@auth-alias',
        'request_method' => '@auth-request-method',
    ];
    private array $ignoreMethod = ['__construct', '__destruct', '__get', '__set', '__isset', '__unset', '__call', '__callStatic', '__toString', '__invoke', '__set_state', '__clone', '__wakeup', '__sleep', '__debugInfo', '__destruct', '__construct', '__destruct', '__get', '__set','__isset', '__unset', '__call', 'index', 'reloadSecondaryMethod'];

    //公共方法
    private array $commonMethod = [ //request_method: 1get 2post
        'index' => [
            'name' => '主页',
            'method_alias' => '/',
            'request_method' => 1,
        ],
        'add' => [
            'name' => '添加页面',
            'method_alias' => 'add',
            'request_method' => 1,
        ],
        'edit' => [
            'name' => '编辑页面',
            'method_alias' => 'edit',
            'request_method' => 1,
        ],
        'del' => [
            'name' => '删除',
            'method_alias' => 'del',
            'request_method' => 4,
        ],
        'state' => [
            'name' => '状态修改',
            'method_alias' => 'state',
            'request_method' => 2,
        ],
        'list' => [
            'name' => '列表',
            'method_alias' => 'list',
            'request_method' => 1,
        ],
        'addPost' => [
            'name' => '添加提交',
            'method_alias' => 'add',
            'request_method' => 2,
        ],
        'editPost' => [
            'name' => '编辑提交',
            'method_alias' => 'edit',
            'request_method' => 2,
        ],
        'save' => [
            'name' => '保存设置',
            'method_alias' => 'save',
            'request_method' => 2,
        ],
    ];
    /**
     * 请求方式
     * @var array|int[]
     */
    private array $requestMethod = [
        'get' => 1,
        'post' => 2,
        'put' => 3,
        'delete' => 4,
    ];

    public function reload($id): array
    {
        $oldController = $this->model->getInfo(['id' => $id, 'level' => 2], 'id, icon, name, module, method, method_alias, request_method, pid, level, sort, is_home_page, show, status');
        if(empty($oldController)){
            return responseArrayMsg('未找到菜单信息');
        }
        $oldMethod = $this->model->getList(['pid' => $oldController['id']], 'id, name, controller, controller_alias, method, method_alias, request_method');
        if(!empty($oldMethod)){
            $arr = $oldMethod;
            $oldMethod = [];
            foreach($arr as $v){
                $oldMethod[$v['method']] = [
                    'name' => $v['name'],
                    'method_alias' => $v['method_alias'],
                    'request_method' => $v['request_method'],
                    'method' => $v['method'],
                    'id' => $v['id'],
                ];
            }
        }
        try {
            $newMethod = $this->getClassMethod('\app\controller\admin\module\\' . $oldController['module'] . '\Index');
        } catch (ReflectionException $e) {
            return responseArrayMsg('未找到控制器信息');
        }
        [$createMethod, $updateMethod, $deleteMethod] = $this->handlerMethod($oldMethod, $newMethod);
        if(empty($createMethod) and empty($updateMethod) and empty($deleteMethod)){
            return responseArrayMsg('暂时还没有什么变化哦!!!', 204);
        }
        if(!empty($createMethod)){
            $createData = [];
            foreach($createMethod as $v){
                $createData[] = [
                    'pid' => $oldController['id'],
                    'name' => $v['name'],
                    'module' => $oldController['module'],
//                    'controller' => $oldController['controller'],
                    'method' => $v['method'],
//                    'controller_alias' => $oldController['controller_alias'],
                    'method_alias' => $v['method_alias'],
                    'request_method' => $v['request_method'],
                    'level' => 3,
                    'show' => 0,
                    'addtime' => time(),
                ];
            }
            $this->model->addAll($createData);
        }
        if(!empty($updateMethod)){
            foreach($updateMethod as $k => $v){
                $this->model->edit(['id' => $oldMethod[$k]['id']], $v);
            }
        }
        if(!empty($deleteMethod)){
            foreach($deleteMethod as $v){
                $this->model->del(['id' => $v['id']]);
            }
        }
        putAdminLog('更新三级菜单|create: [' . json_encode($createMethod) . ']update: [' . json_encode($updateMethod) . ']delete: [' . json_encode($deleteMethod) . ']');
        Position::getInstance()->reload();
        return responseArrayMsg('操作成功', 200);
    }


    /**
     * 筛选出不同的值
     * @param $old
     * @param $new
     * @return array
     */
    private function handlerMethod($old, $new): array
    {
        $create = $update = $delete = [];
        if($old != $new) {
            foreach ($new as $k => $v) {
                if(in_array($k, ['id'])){
                    continue;
                }
                if (!isset($old[$k])) {
                    $create[$k] = $v;
                } else if(is_array($v)){
                    $res = $this->handlerMethod($old[$k], $v);
                    if(!empty($res[0])){
                        $create[$k] = $res[0];
                    }
                    if(!empty($res[1])){
                        $update[$k] = $res[1];
                    }
                    if(!empty($res[2])){
                        $delete[$k] = $res[2];
                    }
                } else if ($old[$k] != $v) {
                    $update[$k] = $v;
                }
            }
            foreach ($old as $k => $v){
                if(in_array($k, ['id'])){
                    continue;
                }
                if (!isset($new[$k])) {
                    $delete[$k] = $v;
                }
            }
        }
        return [$create, $update, $delete];
    }

    /**
     * 获取类里面方法注释
     * @param $className
     * @return array
     * @throws ReflectionException
     */
    private function getClassMethod($className): array
    {
        $methodArray = [];
        $reflectionClass = new ReflectionClass($className);
        $methods = $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC);
        foreach ($methods as $method) {
            if(in_array($method->name, $this->ignoreMethod)){
                continue;
            }
            $comment = $method->getDocComment();
            foreach($this->search as $key => $search){
                preg_match('/' . $search . '\s*([^\r\n@]*)/m', $comment, $matches);
                if(empty($matches)){//没有写标注
                    if(array_key_exists($method->name, $this->commonMethod)){   //如果是公共的方法
                        $methodArray[$method->name][$key] = $this->commonMethod[$method->name][$key];
                    }else{
                        $value = function () use ($method, $key){
                            switch($key){
                                case 'method_alias':
                                case 'name':
                                    return $method->name;
                                case 'request_method':
                                    return 1;
                            }
                            return null;
                        };
                        !empty($value) and $methodArray[$method->name][$key] = $value();
                    }
                    continue;
                }
                $methodArray[$method->name][$key] = $key == 'request_method' ? ($this->requestMethod[$matches[1]] ? : 1 ) : trim($matches[1]);
            }
            isset($methodArray[$method->name]) and $methodArray[$method->name]['method'] = $method->name;
        }
        return $methodArray;
    }

}